package com.ssy.lingxi.pay.controller.mobile.eAccount;

import cn.hutool.core.bean.BeanUtil;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.controller.BaseController;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.model.vo.PageVO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import com.ssy.lingxi.component.redis.utils.SerialNumberUtils;
import com.ssy.lingxi.pay.api.common.EAccountAppletRechargeTypeEnum;
import com.ssy.lingxi.pay.api.common.EAccountJsApiRechargeTypeEnum;
import com.ssy.lingxi.pay.api.common.EAccountMobileRechargeTypeEnum;
import com.ssy.lingxi.pay.api.common.EAccountPCRechargeTypeEnum;
import com.ssy.lingxi.pay.api.common.allInPay.AllInPayEnterpriseStateEnum;
import com.ssy.lingxi.pay.api.common.allInPay.AllInPayPersonalStateEnum;
import com.ssy.lingxi.pay.api.dto.request.eAccount.EAccountCashOutRequest;
import com.ssy.lingxi.pay.api.dto.request.eAccount.EAccountConfirmPayRequest;
import com.ssy.lingxi.pay.api.dto.request.eAccount.EAccountMobileRechargeRequest;
import com.ssy.lingxi.pay.api.dto.response.MapResponse;
import com.ssy.lingxi.pay.api.dto.response.eAccount.EAccountDetailResponse;
import com.ssy.lingxi.pay.api.dto.response.eAccount.EAccountMobileRechargeResponse;
import com.ssy.lingxi.pay.api.model.vo.request.allInPay.BalanceVO;
import com.ssy.lingxi.pay.api.model.vo.request.allInPay.DepositApplyVO;
import com.ssy.lingxi.pay.api.model.vo.request.allInPay.PayVO;
import com.ssy.lingxi.pay.api.model.vo.request.allInPay.WithdrawApplyVO;
import com.ssy.lingxi.pay.api.model.vo.request.allInPay.dto.QueryInExpDetailDTO;
import com.ssy.lingxi.pay.api.model.vo.response.allInPay.*;
import com.ssy.lingxi.pay.common.TradeOperationEnum;
import com.ssy.lingxi.pay.common.TradeStatusEnum;
import com.ssy.lingxi.pay.entity.allInPay.AllInPay;
import com.ssy.lingxi.pay.entity.allInPay.AllInPayAttach;
import com.ssy.lingxi.pay.entity.eAccount.EAccountStatusRecord;
import com.ssy.lingxi.pay.entity.eAccount.EAccountTradeRecord;
import com.ssy.lingxi.pay.model.vo.request.GateWayPayVO;
import com.ssy.lingxi.pay.model.vo.request.ResendPaySMSVO;
import com.ssy.lingxi.pay.model.vo.response.ResendPaySMSRespVO;
import com.ssy.lingxi.pay.service.allInPay.IAllInPayService;
import com.ssy.lingxi.pay.service.eAccount.IEAccountService;
import com.ssy.lingxi.pay.service.eAccount.IEAccountStatusService;
import com.ssy.lingxi.pay.service.eAccount.IEAccountTradeService;
import com.ssy.lingxi.pay.utils.WeChatPayUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @menu: APP-e账户管理-通联
 * @author jw.chen
 * @version 2.0.0
 * @date 2021/12/2
 */
@RestController
@RequestMapping("/pay/mobile/eAccount/allInPay")
public class MobileEAccountController extends BaseController {

    @Resource
    private IEAccountService eAccountService;

    @Resource
    private IEAccountStatusService eAccountStatusService;

    @Resource
    private IAllInPayService payService;

    @Resource
    private IRedisStringUtils redisStringUtils;

    @Resource
    private IEAccountTradeService eAccountTradeService;

    /**
     * 账户详情
     */
    @RequestMapping(value = "/getAccountDetail", method = RequestMethod.GET)
    public Wrapper<EAccountDetailResponse> getAccountDetail() {
        UserLoginCacheDTO sysUser = this.getSysUser();
        AllInPay allInPay = eAccountService.getAccountDetail(sysUser);
        if(allInPay != null){
            //查询账户余额
            BalanceVO balanceVO = payService.queryBalance(sysUser.getMemberId(), sysUser.getMemberRoleId());
            //账户信息
            EAccountDetailResponse eAccountResponse = BeanUtil.copyProperties(allInPay, EAccountDetailResponse.class);
            eAccountResponse.setAccountBalance(balanceVO.getAllAmount());
            eAccountResponse.setLockBalance(balanceVO.getFreeZenAmount());
            eAccountResponse.setUsableBalance(balanceVO.getAvailableAmount());
            eAccountResponse.setPhone(allInPay.getPhone());
            eAccountResponse.setName(allInPay.getName());

            //账户状态
            Integer allInMemberType = allInPay.getAllInMemberType();
            Integer accountStatus = allInPay.getAccountStatus();
            eAccountResponse.setAllInMemberType(allInMemberType);
            if(allInMemberType != null && allInMemberType.equals(3)){
                eAccountResponse.setAccountStatusName(AllInPayPersonalStateEnum.getName(accountStatus));
            }
            if(allInMemberType != null && allInMemberType.equals(2)){
                eAccountResponse.setAccountStatusName(AllInPayEnterpriseStateEnum.getName(accountStatus));
            }

            //账户附属信息
            AllInPayAttach accountAttachDetail = eAccountService.getAccountAttachDetail(allInPay.getBizUserId());
            if(accountAttachDetail != null){
                eAccountResponse.setBranchName(accountAttachDetail.getBranchName());
                eAccountResponse.setAccountNo(accountAttachDetail.getAccountNo());
                eAccountResponse.setBankName(accountAttachDetail.getBankName());
                eAccountResponse.setBankNo(accountAttachDetail.getBankNo());
            }
            return Wrapper.success(eAccountResponse);
        }else{
            throw new BusinessException(ResponseCode.PAY_E_ACCOUNT_NOT_EXIST);
        }
    }

    /**
     * 交易记录
     * @param startTime 开始时间,格式:yyyy-MM-dd HH:mm:ss
     * @param endTime 结束时间,格式:yyyy-MM-dd HH:mm:ss
     */
    @RequestMapping(value = "/getEAccountTradeRecord", method = RequestMethod.GET)
    public Wrapper<PageData<InExpDetail>> getEAccountTradeRecord(PageVO pageVO, @RequestParam("startTime") String startTime, @RequestParam("endTime") String endTime) {
        UserLoginCacheDTO sysUser = this.getSysUser();
        AllInPay allInPay = eAccountService.getAccountDetail(sysUser);
        if(allInPay != null) {
            Integer isSign = allInPay.getIsSign();
            if(isSign == 1){
                QueryInExpDetailDTO dto = new QueryInExpDetailDTO();
                dto.setDateStart(startTime);
                dto.setDateEnd(endTime);
                dto.setQueryNum((long) pageVO.getPageSize());
                dto.setStartPosition((long) pageVO.getCurrentOffset() + 1);
                QueryInExpDetailRespVO queryInExpDetailRespVO = payService.queryInExpDetail(allInPay.getMemberId(), allInPay.getMemberRoleId(), dto);
                if(queryInExpDetailRespVO != null){
                    return Wrapper.success(new PageData<>(queryInExpDetailRespVO.getTotalNum(), queryInExpDetailRespVO.getInExpDetails()));
                }
            }
            return Wrapper.success(new PageData<>(0L, new ArrayList<>()));
        }else{
            throw new BusinessException(ResponseCode.PAY_E_ACCOUNT_NOT_EXIST);
        }
    }

    /**
     * 状态记录
     * @param id e账户id
     */
    @RequestMapping(value = "/getEAccountStatusRecord", method = RequestMethod.GET)
    public Wrapper<List<EAccountStatusRecord>> getEAccountStatusRecord(@RequestParam("id") Long id) {
        return Wrapper.success(eAccountStatusService.getEAccountStatusRecord(id));
    }

    /**
     * 查询充值方式-app
     */
    @RequestMapping(value = "/getRechargeType", method = RequestMethod.GET)
    public Wrapper<List<MapResponse>> getRechargeType() {
        return Wrapper.success(EAccountMobileRechargeTypeEnum.getCodes());
    }

    /**
     * 查询充值方式-小程序
     */
    @RequestMapping(value = "/getAppletRechargeType", method = RequestMethod.GET)
    public Wrapper<List<MapResponse>> getAppletRechargeType() {
        return Wrapper.success(EAccountAppletRechargeTypeEnum.getCodes());
    }

    /**
     * 查询充值方式-h5
     */
    @RequestMapping(value = "/getJsApiRechargeType", method = RequestMethod.GET)
    public Wrapper<List<MapResponse>> getJsApiRechargeType() {
        return Wrapper.success(EAccountJsApiRechargeTypeEnum.getCodes());
    }
    /**
     * 账户充值
     * @param eAccountMobileRechargeRequest 参数
     * @return 操作结果
     */
    @RequestMapping(value = "/recharge", method = RequestMethod.POST)
    public Wrapper<EAccountMobileRechargeResponse> recharge(@RequestBody @Valid EAccountMobileRechargeRequest eAccountMobileRechargeRequest, HttpServletRequest request) {
        UserLoginCacheDTO sysUser = this.getSysUser();
        AllInPay allInPay = eAccountService.getAccountDetail(sysUser);
        if (allInPay != null) {
            String type = eAccountMobileRechargeRequest.getType();
            BigDecimal money = eAccountMobileRechargeRequest.getMoney();
            String message = EAccountMobileRechargeTypeEnum.getMessage(type);
            if (StringUtils.isNotEmpty(message)) {
                //交易订单号
                String tradeCode = SerialNumberUtils.getNumber(redisStringUtils, Constants.ACCOUNT_TRACE_CODE, Constants.REDIS_ORDER_INDEX, Constants.ACCOUNT_TRACE_CODE_DATE, Constants.ACCOUNT_TRACE_CODE_NUM_LEN);

                DepositApplyVO depositApplyVO = new DepositApplyVO();
                depositApplyVO.setAmount(money);
                depositApplyVO.setBizOrderNo(tradeCode);
                depositApplyVO.setFee(new BigDecimal(0));
                depositApplyVO.setPayMethodStr(type);
                if(EAccountPCRechargeTypeEnum.QUICKPAY_VSP.getCode().equals(type)){
                    depositApplyVO.setValidateType(1);
                }else{
                    depositApplyVO.setValidateType(0);
                }

                //微信小程序需要获取openId
                if(EAccountMobileRechargeTypeEnum.WECHATPAY_MINIPROGRAM_ORG.getCode().equals(type)){
                    String jsCode = eAccountMobileRechargeRequest.getJsCode();
                    if(StringUtils.isEmpty(jsCode)){
                        throw new BusinessException(ResponseCode.PAY_E_ACCOUNT_CODE_NOT_EXIST);
                    }
                    Map<String, String> param = eAccountService.getWechatParam(jsCode);
                    depositApplyVO.setSubAppId(param.get("subAppId"));
                    depositApplyVO.setOpenId(param.get("openId"));
                    depositApplyVO.setVspCusId(param.get("merchantId"));
                }

                //微信h5支付需要用到 subAppId
                if (EAccountJsApiRechargeTypeEnum.WECHATPAY_H5_OPEN.getCode().equals(type)) {
                    String subAppId = eAccountService.getWechatSubAppId();
                    String remoteAddrIp = WeChatPayUtil.getRemoteAddrIp(request);
                    depositApplyVO.setSubAppId(subAppId);
                    depositApplyVO.setCusIp(remoteAddrIp);
                }

                DepositApplyRespVO depositApplyRespVO = payService.depositApply(getSysUser(), depositApplyVO);
                if(depositApplyRespVO != null){
                    EAccountTradeRecord eAccountTradeRecord = new EAccountTradeRecord();
                    eAccountTradeRecord.setTradeCode(tradeCode);
                    eAccountTradeRecord.setTradeMoney(money);
                    eAccountTradeRecord.setOperation(TradeOperationEnum.AccountRecharge.getCode());
                    eAccountTradeRecord.setRemark(TradeOperationEnum.AccountRecharge.getMessage());
                    eAccountTradeRecord.setTradeTime(System.currentTimeMillis());
                    eAccountTradeRecord.setStatus(TradeStatusEnum.Paying.getCode());
                    eAccountTradeRecord.setMemberId(sysUser.getMemberId());
                    eAccountTradeRecord.setMemberName(sysUser.getCompany());
                    eAccountTradeRecord.setMemberRoleId(sysUser.getMemberRoleId());
                    eAccountTradeRecord.setMemberRoleName(sysUser.getMemberRoleName());
                    eAccountTradeService.saveEAccountTradeRecord(eAccountTradeRecord);

                    EAccountMobileRechargeResponse eAccountMobileRechargeResponse = new EAccountMobileRechargeResponse();
                    if(EAccountPCRechargeTypeEnum.GATEWAY_VSP.getCode().equals(type)){
                        String remoteAddrIp = WeChatPayUtil.getRemoteAddrIp(request);
                        GateWayPayVO gateWayPayVO = new GateWayPayVO();
                        gateWayPayVO.setBizOrderNo(tradeCode);
                        gateWayPayVO.setConsumerIp(remoteAddrIp);
                        eAccountMobileRechargeResponse.setParam(payService.gateWayPay(sysUser.getMemberId(),sysUser.getMemberRoleId(), gateWayPayVO));
                    }else{
                        eAccountMobileRechargeResponse.setParam(depositApplyRespVO.getPayInfo());
                    }
                    eAccountMobileRechargeResponse.setTradeCode(tradeCode);
                    return Wrapper.success(eAccountMobileRechargeResponse);
                }else{
                    throw new BusinessException(ResponseCode.BUSINESS_ERROR);
                }
            } else {
                throw new BusinessException(ResponseCode.PAY_E_ACCOUNT_NOT_SUPPORT);
            }
        }else{
            throw new BusinessException(ResponseCode.PAY_E_ACCOUNT_NOT_EXIST);
        }
    }

    /**
     * 查询账户充值结果
     * @param tradeCode 交易单号
     */
    @RequestMapping(value = "/getRechargeResult", method = RequestMethod.GET)
    public Wrapper<Boolean> getRechargeResult(@RequestParam("tradeCode") String tradeCode) {
        return Wrapper.success(eAccountTradeService.getRechargeResult(tradeCode));
    }

    /**
     * 账户提现
     * @param eAccountCashOutRequest 参数
     */
    @RequestMapping(value = "/cashOut", method = RequestMethod.POST)
    public Wrapper<Boolean> cashOut(@RequestBody @Valid EAccountCashOutRequest eAccountCashOutRequest) {
        UserLoginCacheDTO sysUser = this.getSysUser();
        AllInPay allInPay = eAccountService.getAccountDetail(sysUser);
        if(allInPay != null){
            //交易订单号
            String tradeCode = SerialNumberUtils.getNumber(redisStringUtils, Constants.ACCOUNT_TRACE_CODE, Constants.REDIS_ORDER_INDEX, Constants.ACCOUNT_TRACE_CODE_DATE, Constants.ACCOUNT_TRACE_CODE_NUM_LEN);

            BigDecimal money = eAccountCashOutRequest.getMoney();
            String bankCardNo = eAccountCashOutRequest.getBankCardNo();

            WithdrawApplyVO withdrawApplyVO = new WithdrawApplyVO();
            withdrawApplyVO.setBizOrderNo(tradeCode);
            withdrawApplyVO.setAmount(money);
            withdrawApplyVO.setBankCardNo(bankCardNo);
            WithdrawApplyRespVO withdrawApplyRespVO = payService.withdrawApply(getSysUser(), withdrawApplyVO);
            if(withdrawApplyRespVO != null){
                EAccountTradeRecord eAccountTradeRecord = new EAccountTradeRecord();
                eAccountTradeRecord.setTradeCode(tradeCode);
                eAccountTradeRecord.setTradeMoney(money);
                eAccountTradeRecord.setOperation(TradeOperationEnum.AccountCashOut.getCode());
                eAccountTradeRecord.setRemark(TradeOperationEnum.AccountCashOut.getMessage());
                eAccountTradeRecord.setTradeTime(System.currentTimeMillis());
                eAccountTradeRecord.setBankCardNo(bankCardNo);
                eAccountTradeRecord.setMemberId(sysUser.getMemberId());
                eAccountTradeRecord.setMemberName(sysUser.getCompany());
                eAccountTradeRecord.setMemberRoleId(sysUser.getMemberRoleId());
                eAccountTradeRecord.setMemberRoleName(sysUser.getMemberRoleName());
                eAccountTradeService.saveEAccountTradeRecord(eAccountTradeRecord);
                return Wrapper.success(true);
            }
            return Wrapper.success(false);
        }else{
            throw new BusinessException(ResponseCode.PAY_E_ACCOUNT_NOT_EXIST);
        }
    }

    /**
     * 查询登录用户的账户余额
     */
    @RequestMapping(value = "/getUserBalance", method = RequestMethod.GET)
    public Wrapper<BalanceVO> getUserBalance() {
        UserLoginCacheDTO sysUser = this.getSysUser();
        AllInPay allInPay = eAccountService.getAccountDetail(sysUser);
        if(allInPay != null){
            //查询账户余额
            return Wrapper.success(payService.queryBalance(sysUser.getMemberId(), sysUser.getMemberRoleId()));
        }else{
            throw new BusinessException(ResponseCode.PAY_E_ACCOUNT_NOT_EXIST);
        }
    }

    /**
     * 重新发送短信验证码(余额支付和快捷支付)
     * @param tradeCode 商户订单交易号
     * @return 操作结果
     */
    @RequestMapping(value = "/reSendPayCode", method = RequestMethod.GET)
    public Wrapper<ResendPaySMSRespVO> reSendPayCode(@RequestParam("tradeCode") String tradeCode) {
        ResendPaySMSVO resendPaySMSVO = new ResendPaySMSVO();
        resendPaySMSVO.setBizOrderNo(tradeCode);
        return  Wrapper.success(payService.reSendPaySMS(resendPaySMSVO));

    }

    /**
     * 确认支付(余额支付和快捷支付)
     * @return 操作结果
     */
    @RequestMapping(value = "/confirmPay", method = RequestMethod.POST)
    public Wrapper<PayRespVO> confirmPay(@RequestBody @Valid EAccountConfirmPayRequest eAccountConfirmPayRequest, HttpServletRequest request) {
        String remoteAddrIp = WeChatPayUtil.getRemoteAddrIp(request);
        PayVO payNo = new PayVO();
        payNo.setBizOrderNo(eAccountConfirmPayRequest.getTradeCode());
        payNo.setVerificationCode(eAccountConfirmPayRequest.getVerificationCode());
        payNo.setConsumerIp(remoteAddrIp);
        return Wrapper.success(payService.pay(getSysUser(), payNo));
    }
}
